#!/usr/bin/python

from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import OVSSwitch, Controller, RemoteController, Host
from mininet.cli import CLI
from mininet.log import setLogLevel, info
from mininet.link import TCLink

class MyTopo(Topo):
    "Simple topology example."

    def build(self):
        # Create switches
        s1 = self.addSwitch('s1', dpid='00:00:00:00:00:00:00:01', protocols='OpenFlow13')
        s2 = self.addSwitch('s2', dpid='00:00:00:00:00:00:00:02', protocols='OpenFlow13')

        # Create hosts
        h1 = self.addHost('h1', ip='192.168.0.101/24')
        h2 = self.addHost('h2', ip='192.168.0.102/24')
        h3 = self.addHost('h3', ip='192.168.0.103/24')
        h4 = self.addHost('h4', ip='192.168.0.104/24')
        h5 = self.addHost('h5', ip='192.168.0.105/24')
        h6 = self.addHost('h6', ip='192.168.0.106/24')

        # Add links with specific bandwidth and delay settings
        linkopts0 = dict(bw=300, delay='1ms', loss=0)
        linkopts1 = dict(bw=100, delay='1ms', loss=0)

        self.addLink(h1, s1, cls=TCLink, **linkopts1)
        self.addLink(h2, s1, cls=TCLink, **linkopts1)
        self.addLink(h3, s1, cls=TCLink, **linkopts1)
        self.addLink(h4, s2, cls=TCLink, **linkopts1)
        self.addLink(h5, s2, cls=TCLink, **linkopts1)
        self.addLink(h6, s2, cls=TCLink, **linkopts1)
        self.addLink(s1, s2, cls=TCLink, **linkopts0)

def startMyNet():
    "Create network and run CLI"
    topo = MyTopo()
    net = Mininet(topo=topo, switch=OVSSwitch, controller=None, autoSetMacs=True, autoStaticArp=True)
    c0 = net.addController('c0', controller=Controller)
    net.start()
    
    # Add OpenFlow rules to the switches
    s1 = net.get('s1')
    s2 = net.get('s2')

    # Rules for s1
    s1.cmd('ovs-ofctl -O OpenFlow13 del-flows s1')
    s1.cmd('ovs-ofctl -O OpenFlow13 add-flow s1 priority=100,in_port=1,actions=push_vlan:0x8100,set_field:4096-\>vlan_vid,output:4')
    s1.cmd('ovs-ofctl -O OpenFlow13 add-flow s1 priority=100,in_port=2,actions=push_vlan:0x8100,set_field:4097-\>vlan_vid,output:4')
    s1.cmd('ovs-ofctl -O OpenFlow13 add-flow s1 priority=100,in_port=3,actions=push_vlan:0x8100,set_field:4098-\>vlan_vid,output:4')
    s1.cmd('ovs-ofctl -O OpenFlow13 add-flow s1 priority=100,dl_vlan=0,actions=pop_vlan,output:1')
    s1.cmd('ovs-ofctl -O OpenFlow13 add-flow s1 priority=100,dl_vlan=1,actions=pop_vlan,output:2')
    s1.cmd('ovs-ofctl -O OpenFlow13 add-flow s1 priority=100,dl_vlan=2,actions=pop_vlan,output:3')

    # Rules for s2
    s2.cmd('ovs-ofctl -O OpenFlow13 del-flows s2')
    s2.cmd('ovs-ofctl -O OpenFlow13 add-flow s2 priority=100,in_port=1,actions=push_vlan:0x8100,set_field:4096-\>vlan_vid,output:4')
    s2.cmd('ovs-ofctl -O OpenFlow13 add-flow s2 priority=100,in_port=2,actions=push_vlan:0x8100,set_field:4097-\>vlan_vid,output:4')
    s2.cmd('ovs-ofctl -O OpenFlow13 add-flow s2 priority=100,in_port=3,actions=push_vlan:0x8100,set_field:4098-\>vlan_vid,output:4')
    s2.cmd('ovs-ofctl -O OpenFlow13 add-flow s2 priority=100,dl_vlan=0,actions=pop_vlan,output:1')
    s2.cmd('ovs-ofctl -O OpenFlow13 add-flow s2 priority=100,dl_vlan=1,actions=pop_vlan,output:2')
    s2.cmd('ovs-ofctl -O OpenFlow13 add-flow s2 priority=100,dl_vlan=2,actions=pop_vlan,output:3')


    CLI(net)
    net.stop()

if __name__ == '__main__':
    setLogLevel('info')
    startMyNet()
